home *** CD-ROM | disk | FTP | other *** search
Text File | 1999-04-26 | 63.5 KB | 2,178 lines | [TEXT/ALFA] |
- ## -*-Tcl-*- (nowrap)
- # ###################################################################
- # Alpha - new Tcl folder configuration
- #
- # FILE: "dialogs.tcl"
- # created: 12/1/96 {5:36:49 pm}
- # last update: 04/26/1999 {16:48:29 PM}
- # Author: Vince Darley
- # E-mail: <darley@fas.harvard.edu>
- # mail: Division of Engineering and Applied Sciences, Harvard University
- # Oxford Street, Cambridge MA 02138, USA
- # www: <http://www.fas.harvard.edu/~darley/>
- #
- # Much copyright (c) 1997-1999 Vince Darley, all rights reserved,
- # rest Pete Keleher, Johan Linde.
- #
- # Reorganisation carried out by Vince Darley with much help from Tom
- # Fetherston, Johan Linde and suggestions from the Alpha-D mailing list.
- # Alpha is shareware; please register with the author using the register
- # button in the about box.
- #
- # Description:
- #
- # Much more flexible dialogs for querying the user about flags and
- # vars. These may be global, mode-dependent, or package-dependent.
- #
- # Things you may wish to do:
- #
- # dialog::pkg_options Pkg
- #
- # creates a dialog for all array entries 'PkgmodeVars'. These
- # must have been previously declared using 'newPref'. These
- # variables are _not_ copied into the global scope; only
- # existing as array entries.
- #
- # Note that rather than setting up traces on variables, you are
- # often better off using the optional proc argument to newPref;
- # the name of a procedure to call if that element is changed by
- # the user.
- #
- # The old procedure 'newModeVar' is obsolete. Use the
- # new procedure 'newPref'. Why? It has optional arguments
- # which allow you to declare:
- #
- # lists
- # indexed lists
- # folders
- # files
- # bindings
- # menu-bindings
- # applications
- # variable-list elements
- # array elements
- #
- # all of which can be set using the same central mode/global
- # dialogs.
- #
- # It also lets you add an optional procedure to call when an
- # item changes... Also if Alpha upgrades to Tcl 8 and namespaces,
- # it is easy to modify that central procedure to fit everything
- # with the new scheme.
- #
- # Most modes will just want to declare their vars using newPref.
- # There is usually no need to do _anything_ else.
- #
- # ---
- #
- # The prefs dialog procs below were based upon Pete Keleher's
- # originals.
- # ###################################################################
- ##
-
- namespace eval dialog {}
- namespace eval global {}
- namespace eval flag {}
-
-
-
- # ◊◊◊◊ Toplevel dialog procedures ◊◊◊◊ #
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::pkg_options" --
- #
- # Make a dialog for the given package, with 'title' for the dialog box.
- # 'not_global' indicates the variables are never copied into the global
- # scope, remaining in their array ${pkg}modeVars (or '$var' if it is given)
- #
- # Results:
- # Nothing
- #
- # Side effects:
- # May modify any of the given package's variables.
- #
- # --Version--Author------------------Changes-------------------------------
- # 1.0 <darley@fas.harvard.edu> original
- # -------------------------------------------------------------------------
- ##
- proc dialog::pkg_options {pkg {title ""} {not_global 1} {var ""}} {
- if {!$not_global} {
- # make sure the package variables are global
- global ${pkg}modeVars
- if {[info exists ${pkg}modeVars]} {
- foreach v [array names ${pkg}modeVars] {
- global $v
- set $v [set ${pkg}modeVars($v)]
- }
- }
- }
- if {$title == ""} {
- set title "Preferences for the '[quote::Prettify $pkg]' package"
- }
- if {$not_global} {
- global dialog::_not_global_flag
- if {$var == ""} {
- set dialog::_not_global_flag ${pkg}modeVars
- } else {
- set dialog::_not_global_flag $var
- }
- }
- set err [catch {dialog::modifyModeFlags $title $not_global $pkg} result]
- if {$not_global} {
- global dialog::_not_global_flag
- set dialog::_not_global_flag ""
- }
- if {$err} {
- error $result
- }
- }
- proc dialog::edit_array {var {title ""}} {
- if {$title == ""} {set title "Contents of '$var' array"}
- dialog::pkg_options "" $title 1 $var
- }
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::variable" --
- #
- # Ask for a value, with default given by the given variable, and using
- # that variable's type (list, file, ...) as a constraint.
- #
- # Currently assumes the variable is a list var, but this will change.
- # -------------------------------------------------------------------------
- ##
- proc dialog::variable {var {title ""}} {
- if {$title == ""} { set title [quote::Prettify $var] }
- return [dialog::optionMenu $title [flag::options $var] \
- [uplevel [list set $var]]]
- }
-
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::paged" --
- #
- # Under development. Not yet usable!
- # -------------------------------------------------------------------------
- ##
- proc dialog::paged {args} {
- getOpts {-pageproc}
- set pages [lindex $args 0]
- lappend dialog -m [concat [lindex $pages 0] $pages] 100 10 200 40
- set xmax -1
- set ymax -1
- set i 1
- foreach page $pages {
- lappend dialog -n $page
- set contents [$opts(-pageproc) $page 20 50]
- set x [lindex $contents 0]
- set y [lindex $contents 1]
- set contents [lindex $contents 2]
- if {$x > $xmax} { set xmax $x }
- if {$y > $ymax} { set ymax $x }
- incr i
- }
- incr ymax 15
- incr xmax 20
- eval dialog -w $xmax -h [expr {$ymax+40}] [dialog::okcancel 10 ymax] $dialog
- }
-
- proc helperApps {} {
- set sigs [info globals *Sig]
- regsub -all {Sig} $sigs {} sigs
- set sig [listpick -p "Change/inspect which helper?" [lsort $sigs]]
- set sig ${sig}Sig
- global $sig
- if {![info exists $sig]} { set $sig "" }
- set nsig [dialog::askFindApp $sig [set $sig]]
- if {$nsig != "" && [set $sig] != $nsig} {
- set $sig $nsig
- global modifiedVars
- lappend modifiedVars $sig
- }
- }
-
- proc suffixMappings {} {
- global filepats
-
- set l1 5
- set w1 38
- set l2 [expr {$l1 + $w1 + 5}]
- set w2 200
- set h 18
- set top 5
- set mar 5
-
- set modes [lsort -ignore [array names filepats]]
- set len [expr {[llength $modes] + 1}]
- set modes1 [lrange $modes 0 [expr {$len/2 - 1}]]
- set modes2 [lrange $modes [expr {$len/2}] end]
-
- foreach m $modes1 {
- lappend items -t $m $l1 $top [expr {$l1 + $w1}] [expr {$top + $h}]
- lappend items -e $filepats($m) $l2 $top [expr {$l2 + $w2}] \
- [expr {$top + $h - 2}]
- incr top [expr {$h + $mar}]
- }
-
- set top2 5
- set l1 [expr {$l2 + $w2 + 20}]
- set l2 [expr {$l1 + $w1 + 5}]
- foreach m $modes2 {
- lappend items -t $m $l1 $top2 [expr {$l1 + $w1}] [expr {$top2 + $h}]
- lappend items -e $filepats($m) $l2 $top2 [expr {$l2 + $w2}] \
- [expr {$top2 + $h - 2}]
- incr top2 [expr {$h + $mar}]
- }
-
- if {$top2 > $top} {
- set top $top2
- }
- incr top $mar
-
- set l1 5
- lappend buts -b OK $l1 $top [expr {$l1 + 60}] [expr {$top + 20}]
- lappend buts -b Cancel [expr {$l1 + 100}] $top [expr {$l1 + 160}] \
- [expr {$top + 20}]
-
- set res [eval "dialog -w [expr {$l2 + $w2 + 10}] -h [expr {$top + 27}]" \
- $buts $items]
-
- if {[lindex $res 0]} {
- set res [lrange $res 2 end]
-
- set changed ""
- foreach m [lsort -ignore [array names filepats]] {
- if {$filepats($m) != [lindex $res 0]} {
- lappend changed [list $m [lindex $res 0]]
- }
- set res [lrange $res 1 end]
- }
-
- foreach pair $changed {
- eval addArrDef filepats [lrange $pair 0 1]
- set filepats([lindex $pair 0]) [lindex $pair 1]
- }
- }
- mode::updateSuffixes
- }
- proc dialog::mode {flags vars {title ""}} {
- set lim [expr {10 - [llength $flags]/4}]
- if {[llength $vars] > $lim } {
- set args {}
- set nvars [llength $vars]
- set j 0
- for {set i 0} {$i < $nvars} {incr i $lim ; set lim 10} {
- lappend args [list "Page [incr j] of ${title}" $flags \
- [lrange $vars $i [expr {$i+$lim -1}]]]
- set flags ""
- }
- dialog::multipage $args
- } else {
- dialog::onepage $flags $vars $title
- }
- }
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::modifyModeFlags" --
- #
- # Currently 'not_global == 0' implies this is a mode, or at least that
- # the variables are stored in ${mm}modeVars(...)
- #
- # 'not_global == 1' implies that the variables are stored in the
- # array given by the value of the variable 'dialog::_not_global_flag'
- #
- # Recently removed a call to mode::updateSuffixes which is not necessary
- # -------------------------------------------------------------------------
- ##
- proc dialog::modifyModeFlags {{title ""} {not_global 0} {mm ""}} {
- global mode invisibleModeVars modifiedArrayElements \
- dialog::_not_global_flag allFlags flag::procs
- # Check whether this is a mode or package, and where variable values
- # are stored, and whether that's at the global level as well as in
- # an array...
- if {$not_global} {
- set storage ${dialog::_not_global_flag}
- if {$title == ""} {
- set title "Preferences for '${mm}' package"
- }
- } else {
- if {$mm == ""} {
- set mm $mode
- if {$mm == ""} {
- alertnote "No mode set!"
- return
- }
- }
- set storage ${mm}modeVars
- if {$title == ""} {
- set title "Preferences for '${mm}' mode"
- }
- }
- # check for mode specific proc
- if {[info commands ${mm}modifyFlags] != ""} {${mm}modifyFlags; return}
- if {[info tclversion] >= 8.0} { set storage ::$storage }
- set flags {}
- set vars {}
- global $storage ${storage}Invisible
- if {[info exists $storage]} {
- set unsortedNames [array names $storage]
- set colors {}
- set rest {}
- foreach i $unsortedNames {
- if {[regexp {Colou?r$} $i]} {
- lappend colors $i
- } else {
- lappend rest $i
- }
- }
-
- foreach v [concat [lsort $rest] [lsort $colors]] {
- if {[info exists invisibleModeVars($v)] \
- || [info exists ${storage}Invisible($v)]} continue
-
- if {[lsearch -exact $allFlags $v] >= 0} {
- lappend flags $v
- } else {
- lappend vars $v
- }
- }
-
- if {[catch {dialog::mode $flags $vars $title} values_items]} {
- return
- }
- set res [lindex $values_items 0]
- set editItems [lindex $values_items 1]
- unset values_items
-
- foreach fset $editItems {
- if {[llength $fset] > 1} {
- set fset [lrange $fset 1 end]
- }
- foreach flag $fset {
- set val [lindex $res 0]
- set res [lrange $res 1 end]
- dialog::postManipulate
- if {$not_global} {
- # it's a package which keeps its vars in the array
- if {[set ${storage}($flag)] != $val} {
- set ${storage}($flag) $val
- lappend modifiedArrayElements [list $flag $storage]
- if {[info exists flag::procs($flag)]} {
- eval [set flag::procs($flag)] [list $flag]
- }
- }
- } else {
- # modes keep a copy of their vars at the global
- # level when active
- global $flag
- if {[set $flag] != $val} {
- set $flag $val
- set ${storage}($flag) $val
- lappend modifiedArrayElements [list $flag $storage]
-
- if {[info exists flag::procs($flag)]} {
- eval [set flag::procs($flag)] [list $flag]
- }
- }
- }
- }
- }
- } else {
- alertnote "The '$mm' mode/package has no preference settings."
- }
-
- hook::callAll dialog::modifyModeFlags $mm $title
-
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::getAKey" --
- #
- # Returns a keystring to be used for binding a key in a menu,
- # using a nice dialog box to ask the user.
- #
- # Possible improvements: we could replace the dialog
- # box with a status-line prompt (which would allow the use of
- # getModifiers to check what keys the user pressed).
- #
- # Now handles 'prefixChar' bindings for non-menu items.
- # i.e. you can use this dialog to bind something to 'ctrl-x ctrl-s',
- # for instance.
- #
- # If the name contains '/' it is considered to be two items,
- # separated by that '/', which are to take the same binding,
- # except that one of them will use the option key.
- #
- # Similarly '//' means use shift, '///' means shift-option,
- # For instance 'dialog::getAKey close/closeAll//closeFloat /W<O'
- # would give you the menu-item for 'close' in the file menu.
- # except these last two aren't implemented yet ;-)
- # --Version--Author------------------Changes-------------------------------
- # 1.0 Johan Linde original
- # 1.1 <darley@fas.harvard.edu> can do non-menu bindings too
- # 1.2 <darley@fas.harvard.edu> handles arrow keys
- # 1.2.1 Johan Linde handles key pad keys
- # -------------------------------------------------------------------------
- ##
- proc dialog::getAKey {{name {}} {keystr {}} {for_menu 1}} {
- global keys::func
- # two lists for any other keys which look better with a text description
- set otherKeys {"<No binding>" "-" Space}
- set otherKeyChars [list "" "" " "]
- if {!$for_menu} {
- lappend otherKeys Left Right Up Down "Key pad =" \
- "Key pad /" "Key pad *" "Key pad -" "Key pad +" "Key pad ."
- lappend otherKeyChars "" "" "\x10" "" Kpad= \
- Kpad/ Kpad* Kpad- Kpad+ Kpad.
- for {set i 0} {$i < 10} {incr i} {
- lappend otherKeys "Key pad $i"
- lappend otherKeyChars Kpad$i
- }
- }
- set nname $name
- set shift-opt [expr {![regsub {///} $nname { so-} $nname]}]
- set shift [expr {![regsub {//} $nname { s-} $nname]}]
- set option [expr {![regsub {/} $nname { o-} $nname]}]
- if {[string length $keystr]} {
- set values "0 0"
- set mkey [keys::verboseKey $keystr normal]
- if {$normal} {
- lappend values "Normal Key"
- } else {
- lappend values $mkey
- set mkey {}
- }
- lappend values [regexp {<U} $keystr]
- lappend values [regexp {<B} $keystr]
- if {!$for_menu} {
- if {[regexp "«(.*)»" $keystr "" i]} {
- if {$i == "e"} {
- lappend values "escape"
- } else {
- lappend values "ctrl-$i"
- }
- } else {
- lappend values "<none>"
- }
- }
- if {$option} {lappend values [regexp {<I} $keystr]}
- lappend values [regexp {<O} $keystr]
- lappend values $mkey
- } else {
- set values {0 0 "" 0 0}
- if {!$for_menu} { lappend values <none> }
- if {$option} {lappend values 0}
- lappend values 0 ""
- }
- if {$for_menu} {
- set title "Menu key binding"
- } else {
- set title "Key binding"
- set prefixes [keys::findPrefixChars]
- foreach i $prefixes {
- lappend prefix "ctrl-$i"
- }
- lappend prefixes e
- lappend prefix "escape"
- }
- if {$name != ""} { append title " for '$name'" }
- set usep [info exists prefix]
- global alpha::modifier_keys
- while {1} {
- # Build box
- set box "-t [list $title] 10 10 315 25 -t Key 10 40 40 55 \
- -m [list [concat [list [lindex $values 2]] \
- [list "Normal key"] $otherKeys ${keys::func}]] 80 40 180 57 \
- -c Shift [list [lindex $values 3]] 10 70 60 85 \
- -c Control [list [lindex $values 4]] 80 70 150 85"
- if {$usep} {
- lappend box -t Prefix 190 40 230 55 \
- -m [concat [list [lindex $values 5]] "<none>" "-" $prefix] \
- 235 40 315 57
- }
- if {$option} {
- lappend box -c [lindex ${alpha::modifier_keys} 2] \
- [lindex $values [expr {5 + $usep}]] 160 70 220 85
- }
- lappend box -c [lindex ${alpha::modifier_keys} 0] \
- [lindex $values [expr {5 + $option +$usep}]] 230 70 315 85
- lappend box -n "Normal key" -e [lindex $values [expr {6 + $option +$usep}]] 50 40 70 55
- set values [eval [concat dialog -w 330 -h 130 -b OK 20 100 85 120 -b Cancel 105 100 170 120 $box]]
- # Interpret result
- if {[lindex $values 1]} {error "Cancel"}
- # work around a little Tcl problem
- regsub "\{\{\}" $values "\\\{" values
- set elemKey [string toupper [string trim [lindex $values [expr {6 + $option +$usep}]]]]
- set special [lindex $values 2]
- set keyStr ""
- if {[lindex $values 3]} {append keyStr "<U"}
- if {[lindex $values 4]} {append keyStr "<B"}
- if {$option && [lindex $values [expr {5 + $usep}]]} {append keyStr "<I"}
- if {[lindex $values [expr {5 + $option +$usep}]]} {append keyStr "<O"}
- if {$usep} {
- set pref [lindex $values 5]
- if {$pref != "<none>"} {
- set i [lsearch -exact $prefix $pref]
- append keyStr "«[lindex $prefixes $i]»"
- }
- }
- if {[string length $elemKey] > 1 && $special == "Normal key"} {
- alertnote "You should only give one character for key binding."
- } else {
- if {$for_menu} {
- if {$special == "Normal key" && [text::Ascii $elemKey] > 126} {
- alertnote "Sorry, can't define a key binding with $elemKey."
- } elseif {$elemKey != "" && $special == "Normal key" && ($keyStr == "" || $keyStr == "<U")} {
- alertnote "You must choose at least one of the modifiers control, option and command."
- } elseif {![regexp {F[0-9]} $special] && $special != "Tab" && $special != "Normal key" && $special != "<No binding>" && $keyStr == ""} {
- alertnote "You must choose at least one modifier."
- } else {
- break
- }
- } else {
- break
- }
- }
- }
- if {$special == "<No binding>"} {set elemKey ""}
- if {$special != "Normal key" && $special != "<No binding>"} {
- if {[set i [lsearch -exact $otherKeys $special]] != -1} {
- set elemKey [lindex $otherKeyChars $i]
- } else {
- set elemKey [text::Ascii [expr {[lsearch -exact ${keys::func} $special] + 97}] 1]
- }
- }
- if {![string length $elemKey]} {
- set keyStr ""
- } else {
- append keyStr "/$elemKey"
- }
- return $keyStr
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::optionMenu" --
- #
- # names is the list of items. An item '-' is a divider, and empty items
- # are not allowed.
- # -------------------------------------------------------------------------
- ##
- proc dialog::optionMenu {prompt names {default ""} {index 0}} {
- if {$default == ""} {set default [lindex $names 0]}
-
- set y 5
- set w [expr {[string length $prompt] > 20 ? 350 : 200}]
- if {[string length $prompt] > 60} { set w 500 }
-
- # in case we need a wide pop-up area that needs more room
- set popUpWidth [eval dialog::_reqWidth $names]
- set altWidth [expr {$popUpWidth + 60}]
- set w [expr {$altWidth > $w ? $altWidth : $w}]
-
- set dialog [dialog::text $prompt 5 y [expr {int($w/6.7)}]]
- incr y 10
- eval lappend dialog [dialog::menu 30 y $names $default $popUpWidth]
- incr y 20
- eval lappend dialog [dialog::okcancel [expr {$w - 160}] y 0]
- set res [eval dialog -w $w -h $y $dialog]
-
- if {[lindex $res 2]} { error "Cancel" }
- # cancel was pressed
- if {$index} {
- # we have to take out the entries correponding to pop-up
- # menu separator lines -trf
- set possibilities [lremove -all $names "-"]
- return [lsearch -exact $possibilities [lindex $res 0]]
- } else {
- return [lindex $res 0]
- }
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::alert" --
- #
- # Identical to 'alertnote' but copes with larger blocks of text, and
- # resizes to that text as appropriate.
- # -------------------------------------------------------------------------
- ##
- proc dialog::alert {args} {
- eval [list dialog::yesno -y "Ok" -n ""] $args
- }
-
- proc dialog::errorAlert {args} {
- eval dialog::alert $args
- error [lindex $args 0]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::yesno" --
- #
- # Make a dialog with between 1 and 3 buttons, representing '1', '0' and
- # error "Cancel" respectively. The names of the first two can be given
- # with '-y name' and '-n name' respectively. The cancel button is
- # only used if a '-c' flag is given (and its name is fixed).
- #
- # The procedure automatically sizes the dialog and buttons to fit the
- # enclosed text.
- # -------------------------------------------------------------------------
- ##
- proc dialog::yesno {args} {
- # too long for Alpha's standard dialog
- getOpts {-y -n}
- set prompt [lindex $args 0]
- set y 5
- set w [expr {[string length $prompt] > 20 ? 350 : 200}]
- if {[string length $prompt] > 60} { set w 500 }
-
- set dialog [dialog::text $prompt 5 y [expr {int($w/6.7)}]]
- incr y 10
- set x 10
- if {[info exists opts(-y)] && $opts(-y) != ""} {
- lappend buttons $opts(-y) "" y
- } else {
- lappend buttons "Yes" "" y
- }
- if {[info exists opts(-n)]} {
- if {$opts(-n) != ""} {
- lappend buttons $opts(-n) "" y
- }
- } else {
- lappend buttons "No" "" y
- }
- if {[info exists opts(-c)]} {
- lappend buttons "Cancel" "" y
- }
- eval lappend dialog [eval dialog::button $buttons]
- if {$x > $w} { set w [expr {$x + 15}] }
- set res [eval dialog -w $w -h $y $dialog]
- if {[lindex $res 0]} {
- return 1
- } elseif {[lindex $res 1]} {
- return 0
- } else {
- error "cancelled"
- }
- }
-
- proc dialog::password {{msg "Please enter password:"}} {
- set values [dialog -w 300 -h 90 -t $msg 10 20 290 35 \
- -e "" 10 40 290 42 -b OK 20 60 85 80 -b Cancel 105 60 170 80]
- if {[lindex $values 2]} {error "Cancel"}
- return [lindex $values 0]
- }
-
- proc global::allPrefs {{which "AllPreferences"}} {
- dialog::resetModified
- global flagPrefs varPrefs
- global::updateHelperFlags
- global::updatePackageFlags
- set AllPreferences [array names flagPrefs]
- set InterfacePreferences {Appearance Electrics Text Tiling Window}
- set Input-OutputPreferences {Backups Files Printer Tags WWW}
- set SystemPreferences [lremove -l $AllPreferences \
- $InterfacePreferences ${Input-OutputPreferences} Packages]
- foreach nm [set [join ${which} ""]] {
- lappend args [list $nm $flagPrefs($nm) $varPrefs($nm)]
- }
- dialog::is_global {
- dialog::global_adjust_flags [dialog::multipage $args]
- }
- }
-
- proc dialog::preferences {menu nm} {
- global flagPrefs varPrefs
- if {[string match "Suffix Mappings" $nm]} {
- return [suffixMappings]
- } elseif {[string match "Menus And Features" $nm]} {
- return [global::menusAndFeatures]
- } elseif {[string match "Edit Prefs File" $nm]} {
- return [global::editPrefsFile]
- }
- if {![info exists flagPrefs($nm)]} {
- set nm "[string toupper [string index $nm 0]][string range $nm 1 end]"
- }
- if {[string match "*Preferences" $nm]} { return [global::allPrefs $nm] }
- if {$nm == "Packages"} { global::updatePackageFlags }
- if {$nm == "Helper Applications"} { global::updateHelperFlags }
- dialog::is_global {
- dialog::global_adjust_flags [dialog::onepage $flagPrefs($nm) $varPrefs($nm) "$nm preferences…"]
- }
- }
-
- # ◊◊◊◊ Finding applications ◊◊◊◊ #
-
-
- proc dialog::askFindApp {var sig} {
- if {$sig == ""} {
- set text "Currently unassigned. Set?"
- } elseif {[catch {nameFromAppl '$sig'} name]} {
- set text "App w/ sig '$sig' doesn't seem to exist. Change?"
- } else {
- set text "Current value is '$name'. Change?"
- }
- if {[dialog::yesno $text]} {
- set nsig [dialog::findApp $var $sig]
- set app [nameFromAppl $nsig]
- if {[dialog::yesno "Are you sure you want to set $var to '$nsig'\
- (mapped to '$app')?"]} {
- return $nsig
- }
- }
- return ""
- }
-
- proc dialog::findApp {var sig} {
- global ${var}s modifiedVars
- if {[info exists ${var}s]} {
- # have a list of items
- set sigs [set ${var}s]
-
- set s 0
- foreach f $sigs {
- if {![catch {nameFromAppl $f} path]} {
- lappend items [file tail $path]
- lappend itemsigs $f
- incr s
- }
- }
- if {$s} {
- lappend items "-" "Locate manually…"
- if {[catch {dialog::optionMenu "Select a new helper for '$var':" \
- $items "" 1} p]} {
- return ""
- }
- # we removed a bunch of items above, so have to look here
- if {$p < $s} {
- return [lindex $itemsigs $p]
- }
- }
- if {!$s || $p >= $s} {
- set nsig [dialog::_findApp $var $sig]
- if {$nsig != ""} {
- if {[lsearch $sigs $nsig] == -1} {
- lappend ${var}s $nsig
- lappend modifiedVars ${var}s
- }
- }
- } else {
- set nsig [lindex $sigs $p]
- }
- return $nsig
- } else {
- return [dialog::_findApp $var $sig]
- }
- }
-
- proc dialog::_findApp {var sig} {
- if {[catch {getfile "Locate new helper for '$var':"} path]} { return "" }
- set nsig [getFileSig $path]
- set app [nameFromAppl $nsig]
- if {$app != $path} {
- alertnote "Appl sig '$nsig' is mapped to '$app', not '$path'. Remove the former, or rebuild your desktop."
- return ""
- }
- return $nsig
- }
-
- # ◊◊◊◊ Global/mode menus ◊◊◊◊ #
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::pickMenusAndFeatures" --
- #
- # Prompt the user to select menus and features either globally or
- # for a given mode. We need to make sure that those items in
- # the mode-list which are also in the global list aren't forgotten
- # (since they are removed from the dialog).
- # -------------------------------------------------------------------------
- ##
- proc dialog::pickMenusAndFeatures {mode} {
- global mode::features global::features
- set all [package::partition $mode]
- set menus1 [lindex $all 0]
- set menus2 [lindex $all 1]
- set menus3 [lindex $all 2]
- set features1 [lindex $all 3]
- set features2 [lindex $all 4]
- set features3 [lindex $all 5]
- set all [eval concat $all]
- # decide on two or three column
- #set endw [expr [llength $all] > 50 ? 560 : 380]
- set endw 560
- set chosen ""
- set notchosen ""
- if {$mode == "global"} {
- set current ${global::features}
- set prefix "Select global #"
- lappend names0 {Select global menus}
- set types [list Usual "" "Other possible"]
- } else {
- foreach pkg [set current [set mode::features($mode)]] {
- if {[lsearch -exact ${global::features} $pkg] != -1} {
- lappend chosen $pkg
- } else {
- if {[string index $pkg 0] == "-"} {
- set pkg [string range $pkg 1 end]
- if {[lsearch -exact ${global::features} $pkg] != -1} {
- # these are the ones which are disabled
- lappend notchosen $pkg
- }
- }
- }
- }
- set prefix "Select # for mode '$mode'"
- lappend names0 "Select menus for mode '$mode'"
- set types [list Usual General "Other possible"]
- }
- set tmpcurrent $current
- while 1 {
- set maxh 0
- set box ""
- set names $names0
- foreach type {menus features off} {
- if {$mode == "global" && $type == "off"} {break}
- set w 20
- set h 45
- set i 0
- if {$type == "off"} {
- set subm "Turn items off"
- set types [list "Usually on for this mode" "Uncheck to disable"]
- set off1 [lsort $chosen]
- set off2 [lsort [lremove -l ${global::features} $chosen]]
- set alloff [concat $off1 $off2]
- } else {
- regsub "\#" $prefix $type subm
- }
- set page 1
- lappend names $subm
- lappend box "-n" $subm
- if {$type == "off"} {
- lappend box -t "These items are currently globally on. You can turn them off just for this mode here." 10 $h [expr {$endw -20}] [expr {$h +15}]
- incr h 20
- }
- foreach block $types {
- incr i
- if {[llength [set ${type}$i]] == 0} {
- continue
- }
- if {$type == "off"} {
- lappend box -t "$block:"
- } else {
- lappend box -t "$block $type:"
- }
- lappend box 10 $h [expr {$w +160}] [expr {$h +15}]
- incr h 20
- foreach m [set ${type}$i] {
- if {$h > 360} {
- if {$h > $maxh} {set maxh $h}
- incr page
- lappend names "$subm page $page"
- lappend box "-n" "$subm page $page"
- set h 45
- lappend box -t "$block $type continued..." 10 $h \
- [expr {$w +260}] [expr {$h +15}]
- incr h 20
- }
- set name [quote::Prettify $m]
- if {$type == "off"} {
- set tick [expr {([lsearch -exact $notchosen $m] < 0)}]
- } else {
- set tick [expr {([lsearch -exact $tmpcurrent $m] >= 0)}]
- }
- lappend box -c $name $tick $w $h [expr {$w + 160}] [expr {$h + 15}]
- incr w 180
- if {$w == $endw} {set w 20; incr h 20}
- }
- if {$w != 20} {
- incr h 30 ; set w 20
- }
- }
- if {$h > $maxh} {set maxh $h}
-
- }
- set h $maxh
- incr h 20
- set values [eval [concat dialog -w $endw -h [expr {$h + 30}] \
- -b OK 20 $h 85 [expr {$h + 20}] \
- -b Cancel 105 $h 170 [expr {$h + 20}] \
- -b Help [expr {$endw -200}] $h [expr {$endw - 140}] [expr {$h + 20}] \
- -b Descriptions [expr {$endw -120}] $h [expr {$endw -20}] [expr {$h + 20}] \
- -m [list $names] [expr {($endw - 220)/2}] 10 $endw 30 $box]]
-
- set names0 [list [lindex $values 4]]
- if {[lindex $values 0]} {break}
- if {[lindex $values 1]} {return $current}
- if {[lindex $values 2]} {
- dialog::describeMenusAndFeatures Help
- }
- if {[lindex $values 3]} {
- dialog::describeMenusAndFeatures Describe
- }
- set tmpcurrent ""
- for {set i 0} {$i < [llength $all]} {incr i} {
- if {[lindex $values [expr {$i + 5}]]} {
- lappend tmpcurrent [lindex $all $i]
- }
- }
- }
-
- for {set i 0} {$i < [llength $all]} {incr i} {
- if {[lindex $values [expr {$i + 5}]]} {lappend chosen [lindex $all $i]}
- }
- if {$mode != "global"} {
- for {set j 0} {$j < [llength [set global::features]]} {incr i ; incr j} {
- if {![lindex $values [expr {$i + 5}]]} {
- # turned one off
- set itm [lindex $alloff $j]
- if {[set idx [lsearch -exact $chosen $itm]] != -1} {
- set chosen [lreplace $chosen $idx $idx "-$itm"]
- } else {
- lappend chosen "-$itm"
- }
- }
- }
- }
- return $chosen
- }
-
- proc dialog::describeMenusAndFeatures {{what "Help"}} {
- set all [package::partition]
- set okmenu [lindex $all 0]
- set okfeature [lindex $all 1]
- set okmode [lindex $all 2]
- set all [eval concat $all]
- # decide on two or three column
- set endw [expr {[llength $all] > 50 ? 560 : 380}]
- if {$what == "Help"} {
- set prefix "Read help for a #"
- } else {
- set prefix "Describe a #"
- }
- foreach m {menu feature mode} {
- regsub "\#" $prefix $m subm
- lappend names $subm
- }
- lappend box -m [concat [list [lindex $names 0]] $names] \
- [expr {($endw - 150)/2}] 10 $endw 30
- set maxh 0
- set wincr 160
- foreach type {menu feature mode} {
- set w 20
- set h 45
- regsub "\#" $prefix $type subm
- lappend box "-n" $subm
- if {$type == "mode"} {set wincr 70}
- foreach m [set ok$type] {
- set name [quote::Prettify $m]
- lappend box -b $name $w $h [expr {$w + $wincr}] [expr {$h + 15}]
- incr w [expr {$wincr +20}]
- if {$w == $endw} {set w 20; incr h 20}
- }
- if {$w > 20} {set w 20; incr h 20}
- if {$h > $maxh} {set maxh $h}
- }
- set h $maxh
- incr h 20
- while 1 {
- set values [eval [concat dialog -w $endw -h [expr {$h + 30}] \
- -b OK 20 $h 85 [expr {$h + 20}] $box]]
- if {[lindex $values 0]} {return}
- # we hit a button
- for {set i 0} {$i < [llength $all]} {incr i} {
- if {[lindex $values [expr {$i + 2}]]} {
- if {$what == "Help"} {
- package::helpFile [lindex $all $i]
- } else {
- package::describe [lindex $all $i]
- }
- break
- }
- }
- }
- }
-
-
- # ◊◊◊◊ Dialog sub-panes ◊◊◊◊ #
-
- set dialog::_not_global_flag ""
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::flag" --
- #
- # Builds a dialog-box page to be used for setting global/mode/package
- # preferences. It can contain preferences for flags (on/off), variables,
- # list items, mode items, files, folders, apps,...
- #
- # Results:
- # part of a script to generate the dialog
- #
- # Side effects:
- # sets maxT to the maximum height desired by the dialog
- #
- # --Version--Author------------------Changes-------------------------------
- # 1.0 Pete Keleher original
- # 2.0 <darley@fas.harvard.edu> much more sophisticated (and complex!)
- # -------------------------------------------------------------------------
- ##
- proc dialog::flag {flags vars {left 20} {top 40} {title {}}} {
- global maxT spelling alpha::prefNames dialog::_not_global_flag mode \
- includeDescriptionsInDialogs
- if {$includeDescriptionsInDialogs || [info tclversion] >= 8.0} {
- cache::read index::prefshelp
- if {[info tclversion] >= 8.0} {
- upvar help help
- }
- if {[regsub {(modeVars)?$} ${dialog::_not_global_flag} "" vprefix]} {
- append vprefix ","
- }
- }
-
- if {$title != ""} {
- lappend args "-t" $title 30 10 400 25
- incr top 25
- }
- # if variable names are very long, switch to 2 columns
- if {$includeDescriptionsInDialogs} {
- set perRow 1
- set width 450
- } else {
- if {[maxListItemLength $flags] > 18} {
- set perRow 2
- set width 225
- } else {
- set perRow 3
- set width 150
-
- }
- }
- set height 15
-
- set ind 0
- set l $left
- foreach f $flags {
- set fname [quote::Prettify $f]
- if {$spelling} {text::british fname}
- if {$includeDescriptionsInDialogs} {
- if {[info exists prefshelp($vprefix$f)]} {
- incr top 10
- eval lappend args [dialog::text \
- [dialog::helpdescription $prefshelp($vprefix$f)] $l top 90]
- incr top -14
- } elseif {[info exists prefshelp($mode,$f)]} {
- incr top 10
- eval lappend args [dialog::text \
- [dialog::helpdescription $prefshelp($mode,$f)] $l top 90]
- incr top -14
- }
- }
- lappend args "-c" $fname [dialog::getFlag $f] \
- $l $top [incr l $width] [expr {$top + $height}]
- if {[incr ind] % $perRow == 0} { set l $left ; incr top $height }
- if {[info tclversion] >= 8.0} {
- if {[info exists prefshelp($vprefix$f)]} {
- lappend help $prefshelp($vprefix$f)
- } elseif {[info exists prefshelp($mode,$f)]} {
- lappend help $prefshelp($mode,$f)
- } else {
- lappend help ""
- }
- }
- }
-
- if {$ind} {
- set top [expr {$top + 20}]
- lappend args -p 100 [expr {$top + 27}] 300 [expr {$top + 28}]
- }
-
- dialog::buildSection $vars top 440 $left args alpha::prefNames
- incr top 30
-
- if {$top > $maxT} {set maxT $top}
- return $args
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::buildSection" --
- #
- # Build a dialog box section for a bunch of preferences. If 'flag_check'
- # is set the prefs can be flags or vars, else just vars.
- #
- # 'yvar' is a variable which contains the current y-pos in the box,
- # and should be incremented as appropriate by this procedure.
- # 'width' is the width of the dialog box (default 420)
- # 'l' is the left indent of all the items (default 20)
- # 'dialogvar' is the variable onto which all the construction code
- # should be lappended. If it is not given, then this proc will
- # return the items.
- # 'names', if given, is an array containing textual replacements for
- # the names of the variables to be used in the box.
- #
- # A minimal call would be:
- #
- # set y 20
- # set build [dialog::buildSection [list fillColumn] y]
- # eval lappend build [dialog::okcancel 20 y]
- # set res [eval dialog -w 480 -h $y $build]
- #
- # -------------------------------------------------------------------------
- ##
- proc dialog::buildSection {vars yvar {width 420} {l 20} {dialogvar ""} {names ""} {flag_check 1}} {
- global flag::list flag::type allFlags spelling alpha::colors mode::features \
- includeDescriptionsInDialogs dialog::_not_global_flag mode
- if {$includeDescriptionsInDialogs || [info tclversion] >= 8.0} {
- cache::read index::prefshelp
- if {[info tclversion] >= 8.0} {
- upvar help help
- }
- }
- if {[regsub {(modeVars)?$} ${dialog::_not_global_flag} "" vprefix]} {
- append vprefix ","
- }
- upvar $yvar t
- if {$dialogvar != ""} {upvar $dialogvar args}
- if {$names != ""} { upvar $names name }
- set height 17
- set lf 135
- set r [expr {$l + $width}]
- set rb [expr {$r -45}]
- foreach vset $vars {
- if {[llength $vset] > 1} {
- incr t 5
- if {[lindex $vset 0] != ""} {
- lappend args "-t" "[lindex $vset 0]" [expr {$l -10}] $t $r [expr {$t +15}]
- incr t 20
- }
- set vset [lrange $vset 1 end]
- }
- foreach v $vset {
- if {$includeDescriptionsInDialogs} {
- if {[info exists prefshelp($vprefix$v)]} {
- incr t 10
- eval lappend args [dialog::text $prefshelp($vprefix$v) $l t 90]
- incr t -14
- }
- }
- if {[info tclversion] >= 8.0} {
- if {[info exists prefshelp($vprefix$v)]} {
- lappend help $prefshelp($vprefix$v)
- } elseif {[info exists prefshelp($mode,$v)]} {
- lappend help $prefshelp($mode,$v)
- } else {
- lappend help ""
- }
- }
-
- set vv [dialog::getFlag $v]
- if {[info exists name($v)]} {
- set vname $name($v)
- } else {
- set vname [quote::Prettify $v]
- }
- if {$spelling} {
- text::british vname
- }
- if {$flag_check && [lcontains allFlags $v]} {
- lappend args "-c" $vname $vv $l $t $r [expr {$t + 15}]
- incr t 15
- continue
- }
- # attempt to indent correctly
- set len [string length $vname]
- if {$len > 40} {
- lappend args "-t" "$vname:" $l $t [expr {$r -30}] [expr {$t + $height}]
- incr t 15
- set indent 100
- set tle ""
- } elseif {$len > 17} {
- set indent [expr {11 + 7 * $len}]
- set tle {"-t" "$vname:" $l $t [expr {$l + $indent}] [expr {$t + $height}]}
- } else {
- set indent $lf
- set tle {"-t" "$vname:" $l $t [expr {$l + $indent}] [expr {$t + $height}]}
- }
-
- if {[info exists flag::list($v)]} {
- incr t 5
- eval lappend args $tle
- set litems [flag::options $v]
- if {[regexp "index" [lindex [set flag::list($v)] 0]]} {
- # set item to index, making sure bad values don't error
- if {[catch {lindex $litems $vv} vv]} { set vv [lindex $litems 0] }
- }
- lappend args "-m" [concat [list $vv] $litems] [expr {$l + $indent -2}] [expr {$t -2}] [expr {$r - 14}] [expr {$t + $height +1}]
- incr t 17
- } elseif {[regexp "Colou?r$" $v]} {
- incr t 5
- eval lappend args $tle
- lappend args "-m" [concat [list $vv] ${alpha::colors}] [expr {$l + $indent -2}] [expr {$t -2}] [expr {$r - 14}] [expr {$t + $height +1}]
- incr t 17
- } elseif {[regexp "Mode$" $v]} {
- incr t 5
- eval lappend args $tle
- if {$vv == ""} { set vv "<none>" }
- lappend args "-m" [concat [list $vv] [concat "<none>" [lsort [array names mode::features]]]] [expr {$l + $indent -2}] $t [expr {$r - 14}] [expr {$t + $height +1}]
- incr t 17
- } elseif {[regexp "Sig$" $v]} {
- eval lappend args $tle
- set vv [dialog::specialView_Sig $vv]
- lappend args "-t" $vv [expr {$l + $indent}] $t $rb [expr {$t + $height +1}]
- eval lappend args [dialog::buttonSet $rb $t]
- incr t 17
- } elseif {[regexp "SearchPath$" $v]} {
- eval lappend args $tle
- if {$vv == ""} {
- lappend args "-t" "No search paths currently set." \
- [expr {$l + $indent}] $t $rb [expr {$t + $height +1}]
- eval lappend args [dialog::buttonSet $rb $t]
- incr t 17
- } else {
- eval lappend args [dialog::buttonSet $rb $t]
- foreach ppath $vv {
- lappend args "-t" [dialog::specialView_file $ppath] \
- [expr {$l + $indent}] $t $rb [expr {$t + $height +1}]
- incr t 17
- }
- }
- } elseif {[regexp "(Path|Folder)$" $v]} {
- eval lappend args $tle
- set vv [dialog::specialView_file $vv]
- lappend args "-t" $vv [expr {$l + $indent}] $t $rb [expr {$t + $height +1}]
- eval lappend args [dialog::buttonSet $rb $t]
- incr t 17
- } elseif {[info exists flag::type($v)]} {
- if {[set flag::type($v)] == "funnyChars"} {
- set vv [quote::Display $vv]
- set eh [expr {1 + [string length $vv] / 60}]
- incr t [expr {7 * $eh}]
- eval lappend args $tle
- incr t [expr {5 -7 * $eh}]
- lappend args "-e" $vv [expr {$l + $indent}] $t $r [expr {$t + $eh * $height}]
- incr t [expr {5 + 17 * $eh}]
- } else {
- eval lappend args $tle
- set vv [dialog::specialView_[set flag::type($v)] $vv]
- lappend args "-t" $vv [expr {$l + $indent}] $t $rb [expr {$t + $height +1}]
- eval lappend args [dialog::buttonSet $rb $t]
- incr t 17
- }
- } else {
- set eh [expr {1 + [string length $vv] / 60}]
- incr t [expr {7 * $eh}]
- eval lappend args $tle
- incr t [expr {5 -7 * $eh}]
- lappend args "-e" $vv [expr {$l + $indent}] $t $r [expr {$t + $eh * $height}]
- incr t [expr {5 + 17 * $eh}]
- }
- }
- }
- if {$dialogvar == ""} {return $args}
- }
- proc dialog::multipage {data} {
- dialog::resetModified
- global maxT
- # in case internal 'command-buttons' are used in the dialog
- while 1 {
-
- set left 20
-
- set names {}
- set editItems {}
- set cmd ""
- set maxT 0
- foreach arg [lsort $data] {
- if {[llength $arg] != 3} {error "Bad structure"}
- lappend names [lindex $arg 0]
- set flags [lindex $arg 1]
- set vars [lindex $arg 2]
- lappend editItems [eval list $flags $vars]
- eval lappend cmd "-n" [list [lindex $arg 0]] [dialog::flag $flags $vars]
- }
-
- set buttons [dialog::okcancel $left maxT]
- set height $maxT
- if {![info exists chosenName]} {set chosenName [lindex $names 0]}
- if {[info exists help]} {
- set res [eval [concat dialog -w 480 -h $height \
- -t "Preferences:" 40 10 125 30 $buttons \
- -b "Help" 410 10 460 28 \
- [list -m [concat [list $chosenName] $names] 140 8 405 30] \
- $cmd -help] [list [concat [list \
- "Click here to save the current settings." \
- "Click here to discard any changes you've made to the settings." \
- "Click here to display textual help on each item in this dialog." \
- "Use this popup menu, or the cursor keys to select a \
- different page of preferences."] $help]]]
- } else {
- set res [eval [concat dialog -w 480 -h $height \
- -t "Preferences:" 40 10 125 30 $buttons \
- -b "Help" 410 10 460 28 \
- [list -m [concat [list $chosenName] $names] 140 8 405 30] \
- $cmd]]
- }
-
- set chosenName [lindex $res 3]
- if {[lindex $res 0]} {
- return [list [lrange $res 4 end] [eval concat $editItems]]
- } else {
- if {[lindex $res 1]} {
- error "Cancel chosen"
- }
- dialog::rememberChanges [list [lrange $res 4 end] [eval concat $editItems]]
- # Either help, or some set or describe type button was pressed
- # We need to ensure we remember anything the user has already
- # changed.
- if {[lindex $res 2]} {
- # help pressed
- set i [lsearch -exact $names [lindex $res 3]]
- dialog::describe [lindex $editItems $i] "Description of [lindex $res 3] prefs"
- } else {
- # a 'set…' button was pressed
- dialog::handleSet [lrange $res 4 end] [eval concat $editItems]
- }
- }
- # end of large while loop
- }
-
- }
-
- proc dialog::rememberChanges {values_items} {
- set res [lindex $values_items 0]
- set editItems [lindex $values_items 1]
- unset values_items
- foreach fset $editItems {
- if {[llength $fset] > 1} {
- set fset [lrange $fset 1 end]
- }
- foreach flag $fset {
- set val [lindex $res 0]
- set res [lrange $res 1 end]
- dialog::postManipulate
- dialog::modified $flag $val
- }
- }
- }
-
- proc dialog::onepage {flags vars {title ""}} {
- dialog::resetModified
- global maxT
- while 1 {
- set left 20
- set maxT 0
- set args [dialog::flag $flags $vars 20 10 $title]
- set height [expr {$maxT + 30}]
- set buttons [dialog::okcancel $left maxT]
- set height $maxT
- if {[info exists help]} {
- set res [eval [concat dialog -w 480 -h $height $buttons \
- -b "Help" 410 10 460 28 $args -help] \
- [list [concat [list \
- "Click here to save the current settings." \
- "Click here to discard any changes you've made to the settings." \
- "Click here to display textual help on each item in this dialog." \
- ] $help]]]
- } else {
- set res [eval [concat dialog -w 480 -h $height $buttons \
- -b "Help" 410 10 460 28 $args]]]
- }
-
- if {[lindex $res 0]} {
- return [list [lrange $res 3 end] [concat $flags $vars]]
- } else {
-
- if {[lindex $res 1]} {
- error "Cancel chosen"
- }
- dialog::rememberChanges [list [lrange $res 3 end] [concat $flags $vars]]
- if {[lindex $res 2]} {
- # help
- dialog::describe [concat $flags $vars] $title
- } else {
- dialog::handleSet [lrange $res 3 end] [concat $flags $vars]
- }
- }
- # big while loop end
- }
-
- }
-
- proc dialog::describe {vars {title ""}} {
- if {$title == ""} {
- set title "Preferences description"
- }
- global flag::list flag::type spelling alpha::colors \
- dialog::_not_global_flag mode
- if {[regsub {(modeVars)?$} ${dialog::_not_global_flag} "" vprefix]} {
- append vprefix ","
- }
- cache::read index::prefshelp
- set height 17
- set lf 135
- set l 20
- set width 420
- set r [expr {$l + $width}]
- set rb [expr {$r -45}]
- set args {}
- set t 35
- set height 0
- set page 1
- set pages {}
- foreach vset $vars {
- if {[llength $vset] > 1} {
- incr t 5
- if {[lindex $vset 0] != ""} {
- lappend args "-t" "[lindex $vset 0]" [expr {$l -10}] $t $r [expr {$t +15}]
- incr t 20
- }
- set vset [lrange $vset 1 end]
- } else {
- #do this so that vars that have whitespace padding (used to force dialog position)
- # are not strip of that space in the next "foreach" statement
- set vset [list [set vset]]
- }
- foreach v $vset {
- set vv [dialog::getFlag $v]
- if {[info exists name($v)]} {
- set vname $name($v)
- } else {
- set vname [quote::Prettify $v]
- }
- if {$spelling} {
- text::british vname
- }
- if {[info exists prefshelp($vprefix$v)]} {
- append vname ": " [dialog::helpdescription $prefshelp($vprefix$v)]
- } elseif {[info exists prefshelp($mode,$v)]} {
- append vname ": " [dialog::helpdescription $prefshelp($mode,$v)]
- } else {
- append vname ": no description"
- }
- eval lappend args [dialog::text $vname $l t 60]
- if {$t > 360} {
- # make another page
- eval lappend pages -n [list "Page $page"] $args
- set args {}
- incr page
- if {$t > $height} {set height $t}
- set t 35
- }
-
- }
-
- }
- if {$page > 1} {
- set t $height
- set height [expr {$t + 40}]
- for {set i 1} {$i <= $page} {incr i} {
- lappend names "Page $i"
- }
- eval lappend pages -n [list "Page $page"] $args
- set res [eval [concat dialog -w 480 -h $height \
- -t [list $title] 60 10 $width 30 \
- -b "Ok" 30 [expr {$t + 10}] 95 [expr {$t +30}] \
- [list -m [concat [list [lindex $names 0]] $names] 400 10 475 30] $pages]]
- } else {
- set height [expr {$t + 40}]
- set res [eval [concat dialog -w 480 -h $height \
- -t [list $title] 60 10 $width 30 \
- -b "Ok" 30 [expr {$t + 10}] 95 [expr {$t +30}] $args]]
- }
- }
-
- proc dialog::helpdescription {hlp} {
- set hlp [split $hlp |]
- if {[llength $hlp] <= 1} {
- return [lindex $hlp 0]
- }
- set res ""
- for {set hi 0} {$hi < [llength $hlp]} {incr hi} {
- set hitem [lindex $hlp $hi]
- if {$hitem != ""} {
- if {$hi == 0} {
- regsub "click this box\\.?" $hitem "turn this item on" hitem
- } elseif {$hi == 2} {
- regsub "click this box\\.?" $hitem "turn this item off" hitem
- }
- append res $hitem ". "
- }
- }
- return $res
- }
-
- # ◊◊◊◊ Dialog utilities ◊◊◊◊ #
- proc dialog::handleSet {res names} {
- # to account for sub-lists in the list of names
- foreach n $names {
- if {[llength $n] > 1} {
- eval lappend newnames [lrange $n 1 end]
- } else {
- lappend newnames $n
- }
- }
- set names $newnames
- unset newnames
- global flag::type
- # a 'set…' button was pressed
- for {set i 0} {$i < [llength $names]} {incr i} {
- if {[lindex $res $i] == 1} {
- set v [lindex $names $i]
- if {[regexp "SearchPath$" $v]} {
- set res [buttonAlert "Perform what action to one of the [quote::Prettify $v]s" "Add" "Remove" "Change" "Cancel"]
- switch -- $res {
- "Add" {
- # this set… pressed
- if {![catch {get_directory -p "New [quote::Prettify $v]:"} newval]} {
- set newval [concat [dialog::getFlag $v] [list $newval]]
- dialog::modified $v $newval
- }
- }
- "Remove" {
- if {![catch {set remove [listpick -p "Remove which items from [quote::Prettify $v]:" -l [dialog::getFlag $v]]}]} {
- # remove them
- set newval [lremove -l [dialog::getFlag $v] $remove]
- dialog::modified $v $newval
- }
- }
- "Change" {
- if {![catch {set change [listpick -p "Change which item from [quote::Prettify $v]:" [dialog::getFlag $v]]}]} {
- # change it
- if {![catch {get_directory -p "Replacement [quote::Prettify $v]:"} newval]} {
- set old [dialog::getFlag $v]
- set i [lsearch -exact $old $change]
- set old [lreplace $old $i $i $newval]
- dialog::modified $v $old
- }
- }
- }
- }
- break
- } elseif {[regexp "(Path|Folder)$" $v]} {
- # this set… pressed
- if {![catch {get_directory -p "New [quote::Prettify $v]:"} newval]} {
- dialog::modified $v $newval
- }
- break
- } elseif {[info exists flag::type($v)]} {
- dialog::specialSet_[set flag::type($v)] $v
- break
- } elseif {[regexp "Sig$" $v]} {
- global $v
- set newval [dialog::findApp $v [set $v]]
- if {$newval != ""} {
- dialog::modified $v $newval
- }
- break
- }
- }
- }
- }
-
- proc dialog::setFlag {name val} {
- global dialog::_not_global_flag
- if {${dialog::_not_global_flag} != ""} {
- global ${dialog::_not_global_flag}
- set ${dialog::_not_global_flag}($name) $val
- } else {
- global $name
- set $name $val
- }
- }
-
- proc dialog::getFlag {name} {
- global dialog::_modified
- if {[info exists dialog::_modified($name)]} {
- return [set dialog::_modified($name)]
- } else {
- return [dialog::getOldFlag $name]
- }
- }
- proc dialog::getOldFlag {name} {
- global dialog::_not_global_flag
- if {${dialog::_not_global_flag} != ""} {
- global ${dialog::_not_global_flag}
- return [set ${dialog::_not_global_flag}($name)]
- } else {
- global dialog::_is_global
- if {[info exists dialog::_is_global]} {
- global global::_vars
- if {[info exists global::_vars] \
- && [set i [lsearch ${global::_vars} $name]] != -1} {
- return [lindex ${global::_vars} [incr i]]
- }
- }
- }
- global $name
- if {[info exists $name]} {
- return [set $name]
- } else {
- alertnote "Global variable '$name' in the dialog isn't set.\r\
- I'll try to fix that."
- return [set $name ""]
- }
- }
-
- proc dialog::is_global {script} {
- global dialog::_is_global
- set dialog::_is_global 1
- catch "[list uplevel $script]"
- unset dialog::_is_global
- }
- proc dialog::resetModified {} {
- global dialog::_modified
- if {[info exists dialog::_modified]} {
- unset dialog::_modified
- }
- }
-
- proc dialog::global_adjust_flags {values_items} {
- global flag::procs modifiedVars global::_vars
- set res [lindex $values_items 0]
- set editItems [lindex $values_items 1]
- unset values_items
- foreach fset $editItems {
- if {[llength $fset] > 1} {
- set fset [lrange $fset 1 end]
- }
- foreach flag $fset {
- set val [lindex $res 0]
- set res [lrange $res 1 end]
- dialog::postManipulate
- if {[info exists global::_vars] \
- && [set i [lsearch ${global::_vars} $flag]] != -1} {
- set orig [lindex ${global::_vars} [incr i]]
- if {$orig != $val} {
- set global::_vars [lreplace ${global::_vars} $i $i $val]
- lappend warn_global $flag
- }
- } else {
- global $flag
- set orig [set $flag]
- if {$orig != $val} {
- set $flag $val
- }
- }
- if {$orig != $val} {
- if {[info exists flag::procs($flag)]} {
- set proc [set flag::procs($flag)]
- if {([info procs $proc] != "") && ([llength [info args $proc]] == 0)} {
- eval $proc
- } else {
- eval $proc [list $flag]
- }
- }
- lappend modifiedVars $flag
- }
- }
- }
- if {[info exists warn_global]} {
- if {[llength $warn_global] == 1} {
- set msg "is a global pref"
- } else {
- set msg "are global prefs"
- }
- alertnote "You modified [join $warn_global {, }] which $msg,\
- but currently over-ridden by mode-specific values. If you meant to\
- modify the latter values, use the mode prefs dialog."
- }
- }
-
- proc dialog::postManipulate {} {
- global flag::list flag::type
- upvar flag f
- upvar val v
-
- if {[info exists flag::list($f)]} {
- switch -- [lindex [set l [set flag::list($f)]] 0] {
- "index" {
- set v [lsearch -exact [lindex $l 1] $v]
- }
- "varindex" {
- set itemv [lindex $l 1]
- global $itemv
- set v [lsearch -exact [set $itemv] $v]
- }
- }
- }
- if {$v == "<none>" && [regexp "Mode$" $f]} { set v "" }
- # This check also captures any 'dialog::modified' items
- # This allows flags which are somehow already set by the
- # dialog (for instance if called recursively, or if set by embedded
- # 'Set…' buttons) to be registered as modifed by our calling procedure.
- if {[regexp "(Path|Folder|Sig)$" $f]} {
- set v [dialog::getFlag $f]
- } elseif {[info exists flag::type($f)]} {
- switch -- [set flag::type($f)] {
- "binding" {
- # setup the changed binding
- set old [dialog::getOldFlag $f]
- set v [dialog::getFlag $f]
- if {$old != $v} {
- global flag::binding
- if {[info exists flag::binding($f)]} {
- set m [lindex [set flag::binding($f)] 0]
- if {[set proc [lindex [set flag::binding($f)] 1]] == 1} {
- set proc $f
- }
- catch "unBind [keys::toBind $old] [list $proc] $m"
- catch "Bind [keys::toBind $v] [list $proc] $m"
- }
- }
- }
- "funnyChars" {
- set v [quote::Undisplay $v]
- }
- default {
- set v [dialog::getFlag $f]
- }
- }
- }
- }
-
- proc dialog::modified {name val} {
- global dialog::_modified
- set dialog::_modified($name) $val
- }
-
- # Used on modified mode flags.
- set flag::procs(stringColor) "stringColorProc"
- set flag::procs(commentColor) "stringColorProc"
- set flag::procs(keywordColor) "stringColorProc"
- set flag::procs(funcColor) "stringColorProc"
- set flag::procs(sectionColor) "stringColorProc"
- set flag::procs(bracesColor) "stringColorProc"
-
- proc global::updateHelperFlags {} {
- uplevel #0 {
- set "flagPrefs(Helper Applications)" {}
- set "varPrefs(Helper Applications)" [info globals *Sig]
- }
- }
-
- proc global::updatePackageFlags {} {
- global flagPrefs varPrefs allFlags modeVars allVars
- # flags can be in either flagPrefs or varPrefs if we're grouping
- # preferences according to function
- set all {}
- set flagPrefs(Packages) {}
- set varPrefs(Packages) {}
- foreach v [array names flagPrefs] {
- eval lappend all $flagPrefs($v)
- if {[info exists varPrefs($v)]} {
- if {[regexp {[{}]} $varPrefs($v)]} {
- # we're grouping
- foreach i $varPrefs($v) {
- if {[llength $i] > 1} {
- eval lappend all [lrange $i 1 end]
- } else {
- lappend all $i
- }
- }
- } else {
- eval lappend all $varPrefs($v)
- }
- }
- }
- foreach f $allFlags {
- if {([lsearch $modeVars $f] < 0)} {
- if {[lsearch -exact $all $f] == -1} {
- lappend flagPrefs(Packages) $f
- }
- }
- }
-
- foreach f $allVars {
- if {([lsearch $modeVars $f] < 0)} {
- if {[lsearch -exact $all $f] == -1} {
- if {[regexp {Sig$} $f]} {
- lappend "varPrefs(Helper Applications)" $f
- } else {
- lappend varPrefs(Packages) $f
- }
- }
- }
- }
- }
-
- #================================================================================
-
- proc maxListItemLength {l} {
- set m 0
- foreach item $l {
- if {[set mm [string length $item]] > $m} { set m $mm }
- }
- return $m
- }
-
- proc stringColorProc {flag} {
- global $flag mode
-
- if {[set $flag] == "none"} {
- set $flag "foreground"
- }
- if {$flag == "stringColor"} {
- regModeKeywords -a -s $stringColor $mode
- } elseif {$flag == "commentColor"} {
- regModeKeywords -a -c $commentColor $mode
- } elseif {$flag == "funcColor"} {
- regModeKeywords -a -f $funcColor $mode
- } elseif {$flag == "bracesColor"} {
- regModeKeywords -a -I $bracesColor $mode
- } elseif {($flag == "keywordColor") || ($flag == "sectionColor")} {
- alertnote "Change in keyword color will take effect after Alpha restarts."
- return
- } else {
- alertnote "Change in $flag color will take effect after Alpha restarts."
- return
- }
- refresh
- }
-
- # ◊◊◊◊ Dialog sub-items ◊◊◊◊ #
-
- proc dialog::buttonSet {x y} {
- return [list -b Set… $x $y [expr {$x + 45}] [expr {$y + 15}]]
- }
-
- proc dialog::okcancel {x yy {vertical 0}} {
- upvar $yy y
- set i [dialog::button "OK" $x y]
- if {!$vertical} {
- incr y -30
- incr x 80
- }
- eval lappend i [dialog::button "Cancel" $x y]
- return $i
- }
-
- proc dialog::menu {x yy item {def "def"} {requestedWidth 0}} {
- upvar $yy y
- set m [concat [list $def] $item]
- if {$requestedWidth == 0} {
- set popUpWidth 340
- } else {
- set popUpWidth $requestedWidth
- }
-
- if {[info tclversion] < 8.0} {
- set res [list -m $m $x $y [expr {$x + $popUpWidth}] [expr {$y +20}]]
- incr y 20
- } else {
- incr y -1
- set res [list -m $m $x $y [expr {$x + $popUpWidth}] [expr {$y +19}]]
- incr y 21
- }
- return $res
- }
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::button" --
- #
- # Create a dialog string encoding one or more buttons. 'name' is the
- # name of the button ("Ok" etc), x is the x position, or if x is null,
- # then we use the variable called 'x' in the calling procedure. yy is
- # the name of a variable containing the y position of the button, which
- # will be incremented by this procedure. if args is non-null, it
- # contains further name-x-yy values to be lines up next to this button.
- # For sequences of default buttons, a spacing of '80' is usual, but
- # it's probably best if you just set the 'x' param to "" and let this
- # procedure calculate them for you. See dialog::yesno for a good
- # example of calling this procedure.
- # -------------------------------------------------------------------------
- ##
- proc dialog::button {name x yy args} {
- upvar $yy y
- if {$x == ""} {
- unset x
- upvar x x
- }
- set add 65
- if {[set i [expr {[string length $name] - 7}]] > 0} {
- incr add [expr {$i * 7}]
- }
- set res [list -b $name $x $y [expr {$x +$add}] [expr {$y +20}]]
- incr x $add
- incr x 15
- if {[llength $args]} {
- eval lappend res [eval dialog::button $args]
- return $res
- }
- incr y 30
- return $res
- }
- proc dialog::title {name w} {
- set l [expr {${w}/2 - 4 * [string length $name]}]
- if {$l < 0} {set l 0}
- return [list -t $name $l 10 [expr {$w - $l}] 25]
- }
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::text" --
- #
- # Creates a text box wrapping etc the text to fit appropriately.
- # In the input text 'name', "\r" is used as a paragraph delimiter,
- # and "\n" is used to force a linebreak. Paragraphs have a wider
- # spread.
- # -------------------------------------------------------------------------
- ##
- proc dialog::text {name x yy {split 0}} {
- upvar $yy y
- if {!$split || $name == ""} {
- set res [list -t $name $x $y [expr {$x + 7 * [string length $name]}] \
- [expr {$y +15}]]
- incr y 18
- } else {
- global fillColumn
- if {[info exists fillColumn]} {
- set f $fillColumn
- }
- set fillColumn $split
- set name [string trim $name]
- set paragraphList [split $name "\r"]
- foreach para $paragraphList {
- set lines ""
- foreach line [split $para "\n"] {
- lappend lines [breakIntoLines $line]
- }
- set lines [join $lines "\r"]
- foreach line [split $lines "\r"] {
- eval lappend res [list -t $line $x $y [expr {$x + 4+ 8 * [string length $line]}] \
- [expr {$y +15}]]
- incr y 18
- }
- incr y 10
- }
- if {[info exists f]} {
- set fillColumn $f
- } else {
- unset fillColumn
- }
- }
- return $res
- }
- proc dialog::edit {name x yy chars {cols 1}} {
- upvar $yy y
- set res [list -e $name $x $y [expr {$x + 10 * $chars}] [expr {$y + 15 * $cols}]]
- incr y [expr {5 + 15*$cols}]
- return $res
- }
- proc dialog::textedit {name default x yy chars {height 1}} {
- upvar $yy y
- set res [list -t $name $x $y [expr {$x + 8 * [string length $name]}]\
- [expr {$y +16}] \
- -e $default $x [expr {$y + 20}] [expr {$x + 10 * $chars}] \
- [expr {$y +20 + 16*$height}]]
- incr y [expr {24 + 16*$height}]
- return $res
- }
- proc dialog::checkbox {name default x yy} {
- upvar $yy y
- set res [list -c $name $default $x $y]
- lappend res [expr {$x + [dialog::_reqWidth $name]}] [expr {$y +15}]
- incr y 18
- return $res
- }
-
- proc dialog::_reqWidth {args} {
- set w 0
- foreach name $args {
- set c [regsub -all -nocase {[wm]} $name "" ""]
- set d [regsub -all {[ il',;:.]} $name "" ""]
- set len [expr {11 * [string length $name] + 6 * $c - 5 * $d}]
- if {$len > $w} {
- set w $len
- }
- }
- return $w
- }
-
- # ◊◊◊◊ Multiple bindings dialogs ◊◊◊◊ #
-
- proc dialog::arrayBindings {name array {for_menu 0}} {
- upvar $array a
- foreach n [array names a] {
- lappend l [list $a($n) $n]
- }
- if {[info exists l]} {
- eval dialog::adjustBindings [list $name modified "" $for_menu] $l
- }
- array set a [array get modified]
- }
-
- ##
- # -------------------------------------------------------------------------
- #
- # "dialog::adjustBindings" --
- #
- # 'args' is a list of pairs. The first element of each pair is the
- # menu binding, and the second element is a descriptive name for the
- # element. 'array' is the name of an array in the calling proc's
- # scope which is used to return modified bindings.
- #
- # Results:
- #
- # --Version--Author------------------Changes-------------------------------
- # 1.0 Johan Linde original for html mode
- # 1.1 <darley@fas.harvard.edu> general purpose version
- # 1.2 Johan Linde split into two pages when many items
- # -------------------------------------------------------------------------
- ##
- proc dialog::adjustBindings {name array {mod {}} {for_menu 1} args} {
- global screenHeight
- regsub -all {\"\(-\"} $args "" items
- upvar $array key_changes
-
- foreach it $items {
- if {[info exists key_changes([lindex $it 1])]} {
- set tmpKeys([lindex $it 1]) $key_changes([lindex $it 1])
- } else {
- set tmpKeys([lindex $it 1]) [lindex $it 0]
- }
- }
- # do we return modified stuff?
- if {$mod != ""} { upvar $mod modified }
- set modified ""
- set page "Page 1 of $name"
- while {1} {
- # Build dialog.
- set twoWindows 0
- set box ""
- set h 30
- foreach it $items {
- if {$it == "(-"} {continue}
- set w 210
- set w2 370
- set key $tmpKeys([lindex $it 1])
- set key1 [dialog::specialView_binding $key]
- set it2 [split [lindex $it 1] /]
- if {[llength $it2] == 1} {
- lappend box -t [lindex $it2 0] 65 $h 205 [expr {$h + 15}] -t $key1 $w $h $w2 [expr {$h + 15}]
- eval lappend box [dialog::buttonSet 10 $h]
- incr h 17
- } else {
- lappend box -t [lindex $it2 0] 65 $h 205 [expr {$h + 15}] -t $key1 $w $h $w2 [expr {$h + 15}]
- eval lappend box [dialog::buttonSet 10 [expr {$h +8}]]
- incr h 17
- if {$key1 != "<no binding>"} {regsub {((ctrl-)?(shift-)?)(.*)} $key1 {\1opt-\4} key1}
- lappend box -t [lindex $it2 1] 65 $h 205 [expr {$h + 15}] -t $key1 $w $h $w2 [expr {$h + 15}]
- incr h 17
- }
- if {$it != [lindex $items [expr {[llength $items] -1}]] && !$twoWindows && [set twoWindows [expr {$h + 100 > $screenHeight}]]} {
- set box " -n [list [concat Page 1 of $name]] $box -n [list [concat Page 2 of $name]] "
- set hmax $h; set h 30
- }
- }
- if {[info exists hmax]} {set h $hmax}
- if {$twoWindows} {
- set top "-m [list [list $page [concat Page 1 of $name] [concat Page 2 of $name]]] 10 10 370 25"
- } else {
- set top "-t [list $name] 50 10 250 25"
- }
- set buttons "-b OK 20 [expr {$h + 10}] 85 [expr {$h + 30}] -b Cancel 105 [expr {$h + 10}] 170 [expr {$h + 30}]"
- set values [eval [concat dialog -w 380 -h [expr {$h + 40}] $buttons $top $box]]
- if {$twoWindows} {set page [lindex $values 2]}
- if {[lindex $values 1]} {
- # Cancel
- return "Cancel"
- } elseif {[lindex $values 0]} {
- # Save new key bindings
- foreach it $modified {
- set key_changes($it) $tmpKeys($it)
- }
- return
- } else {
- # Get a new key.
- set it [lindex [lindex $items [expr {[lsearch $values 1] - 2 - $twoWindows}]] 1]
- if {![catch {dialog::getAKey $it $tmpKeys($it) $for_menu} newKey] && $newKey != $tmpKeys($it)} {
- set tmpKeys($it) $newKey
- lappend modified $it
- }
- }
- }
- }
-
- # ◊◊◊◊ Manipulation of special pref types ◊◊◊◊ #
-
- proc dialog::specialView_binding {key} {
- append key1 [keys::modifiersTo $key "verbose"]
- append key1 [keys::verboseKey $key]
- if {$key1 == ""} { return "<no binding>" }
- return $key1
- }
-
- proc dialog::specialSet_binding {v {menu 0}} {
- # Set… pressed
- set oldB [dialog::getFlag $v]
- if {![catch {dialog::getAKey [quote::Prettify $v] $oldB $menu} newKey] && $newKey != $oldB} {
- dialog::modified $v $newKey
- }
- }
-
- proc dialog::specialView_menubinding {key} {
- dialog::specialView_binding $key
- }
-
- proc dialog::specialSet_menubinding {v} {
- dialog::specialSet_binding $v 1
- }
- proc dialog::specialView_Sig {vv} {
- if {$vv != ""} {
- if {[catch {nameFromAppl $vv} path]} {
- return "Unknown application with sig '$vv'"
- } else {
- return [dialog::specialView_file $path]
- }
- }
- return ""
- }
-
- proc dialog::specialView_io-file {vv} {
- dialog::specialView_file $vv
- }
-
- proc dialog::specialView_file {vv} {
- if {[set sl [string length $vv]] > 33} {
- set vv "[string range $vv 0 8]...[string range $vv [expr {$sl -21}] end]"
- }
- return $vv
- }
- proc dialog::specialSet_file {v} {
- # Set… pressed
- set old [dialog::getFlag $v]
- if {![catch {getfile [quote::Prettify "New $v"] [dialog::getFlag $v]} ff] \
- && $ff != $old} {
- dialog::modified $v $ff
- }
- }
- proc dialog::specialSet_io-file {v} {
- # Set… pressed
- set old [dialog::getFlag $v]
- if {![catch {putfile [quote::Prettify "New $v"] [dialog::getFlag $v]} ff] \
- && $ff != $old} {
- dialog::modified $v $ff
- }
- }
-
-
-
-
-
-